#include "ArchivoDeEstructurasFijas.h"
using namespace Archivos;
using namespace Entidades;

ArchivoDeEstructurasFijas::ArchivoDeEstructurasFijas(string path, unsigned int tamanioDeLasEstructuras) :
	Archivo(path) {
	if (tamanioDeLasEstructuras > 0)
		this->tamanioDeLasEstructuras = tamanioDeLasEstructuras;
	else
		this->tamanioDeLasEstructuras = 512; //by default
}

/* Leo a la entidad que se encuentra desde la posiciónEnElArchivo hasta el tamañoDeLasEstructuras */
void ArchivoDeEstructurasFijas::leer(IEntidad* entidad, unsigned int numeroDeEstructura) {

	//traduzco la posicionEnElArchivo
	unsigned int posicionEnElArchivo = this->traducirNumeroDeEstructuraAPosicion(numeroDeEstructura);

	//inicializo el buffer con el tamaño deseado
	int tamanioDelBuffer = this->tamanioDeLasEstructuras;
	char* buffer = new char[tamanioDelBuffer];

	abrirArchivo();

	//coloco al archivo en la posición inicial de la entidad
	archivo.seekg(posicionEnElArchivo, ios::beg);

	//escribo a la entidad en el buffer
	archivo.read(buffer, tamanioDelBuffer);

	cerrarArchivo();

	//lleno la entidad con el buffer
	entidad->hidratarse(buffer, tamanioDelBuffer);

	//como terminé de usarlo, borro el buffer
	delete [] buffer;
}

/* Inserta a la nueva entidad al final del archivo.
 * Retorna posición de la entidad insertada en el archivo.  */
unsigned int ArchivoDeEstructurasFijas::insertar(IEntidad* entidad) {

	//sstream para crear el bloque a escribir en el archivo
	stringstream* ss = new stringstream(stringstream::in | stringstream::out | stringstream::binary);
	ss->seekp(0, ios::end);

	char* bufferEntidad = entidad->construirBuffer();
	ss->write(bufferEntidad,entidad->getTamanioDelBuffer());

	//relleno con vacio hasta la capacidad del bloque
	unsigned int tamanioRelleno = (this->tamanioDeLasEstructuras - entidad->getTamanioDelBuffer());
	char* relleno = new char[tamanioRelleno];
	for (unsigned int i= 0; i< tamanioRelleno;i++){
		relleno[i]= ' ';
	}
	ss->write(relleno,tamanioRelleno);

	//construyo el buffer que se va a guardar en el archivo
	int tamanioDelBuffer = this->tamanioDeLasEstructuras; //siempre el mismo tamaño a insertar
	char* buffer = new char[tamanioDelBuffer];
	ss->read(buffer, tamanioDelBuffer);

	delete ss;

	unsigned int posicionDeEscritura = 0;

	abrirArchivo();

	archivo.seekp(0, ios::end);
	posicionDeEscritura = archivo.tellp();
	archivo.write(buffer, tamanioDelBuffer);

	cerrarArchivo();

	delete [] bufferEntidad;
	delete [] buffer;
	delete [] relleno;
	return this->traducirPosicionANumeroDeEstructura(posicionDeEscritura);
}

unsigned int ArchivoDeEstructurasFijas::modificar(IEntidad* entidad, unsigned int numeroDeEstructura) {

	//sstream para crear el bloque a escribir en el archivo
	stringstream* ss = new stringstream(stringstream::in | stringstream::out | stringstream::binary);
	ss->seekp(0, ios::end);

	//piso toda la estructura fija
	char* bufferEntidad = entidad->construirBuffer();
	ss->write(bufferEntidad,entidad->getTamanioDelBuffer());

	//relleno con vacio hasta la capacidad del bloque
	unsigned int tamanioRelleno = (this->tamanioDeLasEstructuras - entidad->getTamanioDelBuffer());
	char* relleno = new char[tamanioRelleno];
	for (unsigned int i= 0; i< tamanioRelleno;i++){
		relleno[i]= ' ';
	}
	ss->write(relleno,tamanioRelleno);

	//construyo el buffer que se va a guardar en el archivo
	int tamanioDelBuffer = this->tamanioDeLasEstructuras; //siempre el mismo tamaño a insertar
	char* buffer = new char[tamanioDelBuffer];
	ss->read(buffer, tamanioDelBuffer);

	delete ss;

	unsigned int posicionEnElArchivo = this->traducirNumeroDeEstructuraAPosicion(numeroDeEstructura);

	abrirArchivo();

	archivo.seekg(posicionEnElArchivo, ios::beg);
	archivo.write(buffer, tamanioDelBuffer);

	cerrarArchivo();

	delete [] bufferEntidad;
	delete [] buffer;
	delete [] relleno;
	return this->traducirPosicionANumeroDeEstructura(posicionEnElArchivo);
}

/* Encuentro la entidad, la marco como borrada y la guardo.
 * Retorno true si el borrado fue exitoso */
bool ArchivoDeEstructurasFijas::borrar(IEntidad* entidad, unsigned int numeroDeEstructura) {

	entidad->marcarComoBorrado();

	//sstream para crear el bloque a escribir en el archivo
	stringstream* ss = new stringstream(stringstream::in | stringstream::out | stringstream::binary);
	ss->seekp(0, ios::end);

	//piso toda la estructura fija
	char* bufferEntidad = entidad->construirBuffer();
	ss->write(bufferEntidad,entidad->getTamanioDelBuffer());

	//relleno con vacio hasta la capacidad del bloque
	unsigned int tamanioRelleno = (this->tamanioDeLasEstructuras - entidad->getTamanioDelBuffer());
	char* relleno = new char[tamanioRelleno];
	for (unsigned int i= 0; i< tamanioRelleno;i++){
		relleno[i]= ' ';
	}
	ss->write(relleno,tamanioRelleno);

	//construyo el buffer que se va a guardar en el archivo
	int tamanioDelBuffer = this->tamanioDeLasEstructuras; //siempre el mismo tamaño a insertar
	char* buffer = new char[tamanioDelBuffer];
	ss->read(buffer, tamanioDelBuffer);

	delete ss;

	unsigned int posicionEnElArchivo = this->traducirNumeroDeEstructuraAPosicion(numeroDeEstructura);

	abrirArchivo();

	archivo.seekp(posicionEnElArchivo, ios::beg);
	archivo.write(buffer, tamanioDelBuffer);

	cerrarArchivo();

	delete [] bufferEntidad;
	delete [] buffer;
	delete [] relleno;
	return true;
}

/* Devuelve el número de la entidad que contiene a esa posición en el archivo. */
unsigned int ArchivoDeEstructurasFijas::traducirPosicionANumeroDeEstructura(unsigned int posicionEnElArchivo) {
	return (posicionEnElArchivo / this->tamanioDeLasEstructuras);
}

/* Devuelve la posición inicial de la estructura en el archivo. */
unsigned int ArchivoDeEstructurasFijas::traducirNumeroDeEstructuraAPosicion(unsigned int numeroDeEstructura) {
	return (numeroDeEstructura * this->tamanioDeLasEstructuras);
}

int ArchivoDeEstructurasFijas::getCantidadDeEstructuras(){
	abrirArchivo();
    archivo.seekp(0, ios::end);
    int fin = archivo.tellp();
	cerrarArchivo();
	return (fin/this->tamanioDeLasEstructuras);
}
ArchivoDeEstructurasFijas::~ArchivoDeEstructurasFijas() {
}
